/**
 * 1. 创建一个promise类,并在构造函数中传入一个执行器,该执行器执行类的 resolve & reject 方法,防止报错,捕获执行器错误,当执行器报错时,调用reject
 * 2. 一个Promise有三种状态,pending | fulfilled | rejected 状态由 pending => fulfilled || rejected 后,就不可再更改
 * 3. 实现then方法,then方法接收2个回调函数,分别是 successCallback & failCallback
 * 4. 在then方法中,如果currentPromise.status === fulfilled || rejected ,分别调用successCallback || failCallback,如果当前状态是pending(异步),那么需要将回调函数缓存,直到状态改变再调用
 * 5. 当then方法多次被调用时,需要添加多个处理函数
 * 6. 实现 then 方法的链式调用, 需要在then 方法中返回promise对象 // 下一个then的值就是上一个then的返回值; 
 * 7. 需要对then方法的回调函数返回值做判断,该返回值是普通值=>直接调用resolve传递给下一个then; 返回值是Promise对象 => 根据promise对象的返回值决定调用 resolve还是reject ; 返回值是currentPromise => throw Error // promise loop!
 * 8. 添加对then方法的回调函数返回值的错误捕获机制,返回值报错时,执行reject方法传递给下一个then
 * 9. 实现then方法的参数是可选参数,即then().then(res=>{在这拿到参数})
 */

 // 状态定义
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

/**
 * 回调函数返回值做判断
 * @param {*} promise CurrentPromise
 * @param {*} result callback.result
 * @param {*} resolve 
 * @param {*} reject 
 */
function resolvePromise(promise,result,resolve,reject) {
    // *7 
    if(promise === result){
        // 返回值是currentPromise => throw Error // promise loop!
        reject(new Error('Promise is loop!'))
        return 
    }

    if(result instanceof MyPromise){

        // 返回值是Promise对象 => 根据promise对象的返回值决定调用 resolve还是reject 
        result.then(resolve,reject)
    } else {
        // 返回值是普通值=>直接调用resolve传递给下一个then
        resolve(result)
    }
}

class MyPromise {
    constructor(executor){
        // *1
        try {
            executor(this.resolve,this.reject)
        } catch (error) {
            this.reject(error)
        }
    }

    status = PENDING
    // *5 为什么要存成数组? 多次调用then方法时有多个回调函数需要处理
    successCallback = []
    failCallback = []

    successValue;
    failReason;

    resolve = (val)=>{
        // *2
        if(this.status !== PENDING) return 
        this.successValue = val
        // 成功后改变Promise状态
        this.status = FULFILLED
        while (this.successCallback.length) {
            // 依次执行回调函数
            this.successCallback.shift()()
        }
    }
    
    reject = (val) =>{
        // *2
        if(this.status !== PENDING) return 
        this.failReason = val
         // 成功后改变Promise状态
        this.status = REJECTED
          while (this.failCallback.length) {
            // 依次执行回调函数
            this.failCallback.shift()()
        }
    }

    then = (successCallback,failCallback) => {
        // *9. 实现then方法的参数是可选参数
        successCallback = successCallback?successCallback:value=>value ;
        failCallback = failCallback?failCallback:reason=>  {throw new Error(reason)} ;
        const promise = new MyPromise((resolve,reject)=>{
            // 调用resolve实际上就是将值传递给下一个then方法的成功回调,reject同理
            switch (this.status) {
                    case FULFILLED:
                        setTimeout(() => {
                             const val = successCallback(this.successValue)
                                resolvePromise(promise,val,resolve,reject)
                        }, 0);
                       
                        break;
                    case REJECTED:
                        setTimeout(() => {
                             const reason = failCallback(this.failReason)
                            resolvePromise(promise,reason,resolve,reject)
                        }, 0);
                       
                        break;
                    default:
                       /**
                        *  异步执行事状态为pending,缓存回调函数
                        *  如果直接push(callback),无法处理
                        */
                        this.successCallback.push(()=>{
                           setTimeout(() => {
                             const val = successCallback(this.successValue)
                                resolvePromise(promise,val,resolve,reject)
                        }, 0);
                        })
                        this.failCallback.push(()=>{
                           setTimeout(() => {
                             const reason = failCallback(this.failReason)
                            resolvePromise(promise,reason,resolve,reject)
                        }, 0);
                        })
                        break;
                }
        })
        // *6
        return promise
    }

    /** 
     * 捕获失败,并处理失败的情况,返回一个promise对象
     * 接收一个错误信息
     * catch只处理失败信息,所以只需要传入then方法的failCallback参数
     */
    catch = (err) =>{
        return this.then(undefined,()=>this.reject(Error(err)))
    }

    /**
     * @params callback 接收一个回调函数
     * 无论status === fulfilled || rejected ;finally总会执行
     * 实现链式调用,返回一个Promise对象
     */
    finally = (callback) =>{
        return this.then(res=>{
           return callback(res)
        },err=>{
           return callback(err)
        })
    }

    /** Promise.resolve 解析promise对象 */
    static resolve = (value)=>{
        // 判断接收的参数是Promise对象还是普通对象
        if(value instanceof MyPromise){
            // promise对象直接返回
            return value
        } 
         // 普通值则创建一个promise对象,并返回该对象的执行结果 
        return new MyPromise((resolve,reject)=>{
            resolve(value)
        })
    }
    /** 
     * Promise.reject 返回一个被拒绝的Promise对象 
     * @param reason 表示Promise被拒绝的原因。
    */
    static reject = (reason)=>{
       
         // 创建一个promise对象
        return new MyPromise((resolve,reject)=>{
            reject(reason)
        })
    }

    /**
     * 返回一个promise对象
     * 一旦arr中的某个promise解决或失败,则返回该promise的返回值
     * @param {*} arr  数组
     */
    static race = (arr)=>{
        return new MyPromise((resolve,reject)=>{
            let flag = false
            for (let i = 0; i < arr.length; i++) {
                const current = arr[i];
                if(current instanceof MyPromise){
                    current.then(res=>{
                      resolve(res)
                      flag = true
                    },err=>{
                      reject(err)
                      flag = true

                    })
                    if(flag){
                        break
                    }
                } else {
                    resolve(current)
                    break
                }
            }
        })
        
    }

    /** 
     *  Promise.all方法接收一个数组参数,最终返回一个Promise对象
     *  一旦有一个数组元素产生错误,则失败的原因是第一个失败 promise 的结果。
     */
    static all = (arr)=>{
        return new MyPromise((resolve,reject)=>{
            const result = []
            let index = 0
         
            for (let i = 0; i < arr.length; i++) {
                const current = arr[i];
                if(current instanceof MyPromise){
                    // promise 对象
                    current.then(res=>{
                        addResult(i,res)
                    },err=>{
                        reject(err)
                    })
                } else {
                    addResult(i,current)
                }
                
            }
            function addResult(key,data) {
                // 对位放入执行结果
                result[key] = data
                // 确保异步代码执行完成
                index += 1
                // 返回结果集
                if(index ===  arr.length){
                    resolve(result);
                }
            }
          
           
        })
    }
}
module.exports = MyPromise